// Copyright (c) Microsoft Corporation.  All rights reserved.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using PfRep.Library;
using System.Runtime.InteropServices;
using System.Threading;

namespace PfRep.Console
{
    public partial class IndexFolderTree : Form
    {
        /// <summary>
        /// This is the worker thread does the indexing job. We have to
        /// keep a reference in case if we want to shut it down.
        /// </summary>
        private Thread backgroundIndexingThread = null;
        
        /// <summary>
        /// The newly created folder tree's name
        /// </summary>
        public string NewlyCreatedFolderTreeName = "";

        /// <summary>
        /// Indicates whether the user has cancelled the process or a new
        /// tree was succesfully created
        /// </summary>
        public bool UserCancelled = false;

        /// <summary>
        /// The number of public folders to index
        /// </summary>
        private int _numberOfPublicFolders = 0;

        /// <summary>
        /// Retrieves the username typed
        /// </summary>
        public string Username
        {
            get { return txtUsername.Text; }
        }

        /// <summary>
        /// Retrieves the password typed
        /// </summary>
        public string Password
        {
            get { return txtPassword.Text; }
        }
        
        public IndexFolderTree()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Set the OK button if the name changes
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void txtTreeName_TextChanged(object sender, EventArgs e)
        {
            SetOkButton();
        }

        /// <summary>
        /// Set the OK button if the Url changes
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmbPublicFolderUrl_TextChanged(object sender, EventArgs e)
        {
            SetOkButton();
        }

        /// <summary>
        /// Enables/disables the OK button, based whether there are selected values in
        /// both comboboxes
        /// </summary>
        private void SetOkButton()
        {
            // If both options are selected, the OK button gets enabled, otherwise, disabled
            if (txtTreeName.Text.Length > 0 && cmbPublicFolderUrl.Text.Length > 0)
                cmdOK.Enabled = true;
            else
                cmdOK.Enabled = false;
        }

        /// <summary>
        /// Saves the input controls' values
        /// </summary>
        private void SaveInputControlValues()
        {
            // Save the username and last URL
            Common.Config.SetConfigValue("LastUsername", txtUsername.Text);
            Common.Config.SetConfigValue("LastUrl", cmbPublicFolderUrl.Text);

            // Save the URL to history
            string enteredUrls = Common.Config.GetConfigValue("UrlHistory");
            if (string.IsNullOrEmpty(enteredUrls) || enteredUrls.Length == 0)
                enteredUrls = ";" + cmbPublicFolderUrl.Text + ";";
            else if (!enteredUrls.Contains(";" + cmbPublicFolderUrl.Text + ";"))
                enteredUrls = enteredUrls + cmbPublicFolderUrl.Text + ";";
            Common.Config.SetConfigValue("UrlHistory", enteredUrls);

            // Refresh the configuration
            Common.Config.RefreshConfig();
        }

        /// <summary>
        /// Fills up the controls in the form with the previously
        /// used values if there are any
        /// </summary>
        private void FillUpControlsWithPastValues()
        {
            // Fill up the input controls
            txtUsername.Text = Common.Config.GetConfigValue("LastUsername");
            if (txtUsername.Text.Length == 0)
                txtUsername.Text = "DOMAIN\\username";

            // Fill up history
            string enteredUrls = Common.Config.GetConfigValue("UrlHistory");
            if (enteredUrls.Length > 0 && enteredUrls[0].CompareTo(';') == 0)
                enteredUrls = enteredUrls.Remove(0, 1);
            if (enteredUrls.Length > 0 && enteredUrls[enteredUrls.Length - 1].CompareTo(';') == 0)
                enteredUrls = enteredUrls.Remove(enteredUrls.Length - 1, 1);
            string[] urlHistory = enteredUrls.Split(';');
            cmbPublicFolderUrl.Items.Clear();
            cmbPublicFolderUrl.Items.AddRange(urlHistory);

            // Choose the last one
            cmbPublicFolderUrl.Text = Common.Config.GetConfigValue("LastUrl");
            if (cmbPublicFolderUrl.Text.Length == 0)
                cmbPublicFolderUrl.Text = "http://myserver/public";
        }

        /// <summary>
        /// Start creating the index
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmdOK_Click(object sender, EventArgs e)
        {
            // Save input control values
            SaveInputControlValues();

            // Save the index's name
            NewlyCreatedFolderTreeName = txtTreeName.Text;
            
            // Get the number of public folders
            lblCurrentOperation.Text = "Getting the number of public folders";

            IndexManager indexManager = new IndexManager();
            
            // Subscribing for the event handlers
            indexManager.ProgressChanges += new IndexingProgress(ProgressChanges);
            indexManager.IndexingCompleted += new IndexingCompleted(IndexingCompleted);
            
            // Set up the information label
            lblCurrentOperation.Text = "Recursing and indexing public folders";
            
            // Disable cross-thread synchronization check (we know what we do) ...
            Control.CheckForIllegalCrossThreadCalls = false;
            
            // Prepare index parameters and start the thread
            backgroundIndexingThread = new Thread(
                new ParameterizedThreadStart(ThreadProc));
            backgroundIndexingThread.Start(new IndexInputParams(indexManager, cmbPublicFolderUrl.Text,
                txtUsername.Text, txtPassword.Text, txtTreeName.Text));
        }

        /// <summary>
        /// Cancel button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmdCancel_Click(object sender, EventArgs e)
        {
            // Kill the thread if it's already running
            if (backgroundIndexingThread != null)
                backgroundIndexingThread.Abort();

            UserCancelled = true;
        }

        #region Asynchronous processing functions - UI handlers, etc
        /// <summary>
        /// This is a function that starts the asynchronous processing
        /// </summary>
        /// <param name="stateInfo"></param>
        private void ThreadProc(object stateInfo)
        {
            // Convert the input params to the correct format
            IndexInputParams inputParams = stateInfo as IndexInputParams;

            // Extract the parameters and convert them to parameters on a function call
            if (inputParams != null)
                inputParams.IndexManager.CreatePublicFolderIndex(inputParams.PublicFolderUrl,
                    inputParams.Username, inputParams.Password, inputParams.TreeName);
            else
                PfRep.Common.Diagnostics.Trace("ThreadProc", 
                    "ERROR: stateInfo is not IndexInputParams format");
        }

        /// <summary>
        /// Fires whenever a folder index progress occurs
        /// </summary>
        /// <param name="currentItemName"></param>
        /// <param name="currentItemUrl"></param>
        /// <param name="itemNumber"></param>
        /// <param name="itemCount"></param>
        private void ProgressChanges(
            string currentItemName,
            string currentItemUrl,
            int currentItemNumber,
            int itemCount)
        {
            //IndexingProgress.Value = currentItemNumber;
            lblCurrentItem.Text = string.Format("Current item: {0}", currentItemName);
            lblProgress.Text = string.Format("{0} folders discovered so far", currentItemNumber, _numberOfPublicFolders);
        }

        /// <summary>
        /// Called when the indexing is completed
        /// </summary>
        private void IndexingCompleted()
        {
            // Close the window
            this.Close();
        }

        /// <summary>
        /// Called when an error occurred while indexing on the 2nd thread
        /// </summary>
        /// <param name="e"></param>
        private void IndexingError(Exception e)
        {
            if (e is COMException)
            {
                MessageBox.Show("Exchange Server cannot be connected or permission denied. " +
                    "Check the Url, username and password then try again.",
                    "PfRep", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
            else
            {
                MessageBox.Show("An unknown error occurred while indexing the folders. " +
                    "For more information see the trace log (debug version only) " +
                    e.Message, "PfRep", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        #endregion

        private void IndexFolderTree_Load(object sender, EventArgs e)
        {
            // Set the OK button's clickability
            SetOkButton();

            // Set default values for controls
            FillUpControlsWithPastValues();
        }
    }
}